#define MAX_SHADER_MATRICES 60

// Array of instance transforms used by the VFetch and ShaderInstancing techniques.
float4x4 instanceTransforms[MAX_SHADER_MATRICES];

// Camera settings.
float4x4 view;
float4x4 projection;

// This sample uses a simple Lambert lighting model.
float3 lightDirection = normalize(float3(-1, -1, -1));
float3 diffuseLight = 1.25;
float3 ambientLight = 0.25;


struct VS_INPUT
{
	float4 Position : POSITION0;
	float3 Normal	: NORMAL;
	float2 TexCoord : TEXCOORD0;
};

struct VS_OUTPUT
{
	float4 Position     : POSITION;
	float4 Color		: COLOR0;
	float2 TexCoord : TEXCOORD0;
};

VS_OUTPUT VertexShaderCommon(VS_INPUT input, float4x4 instanceTransform)
{
    VS_OUTPUT output;

    // Apply the world and camera matrices to compute the output position.
    float4 worldPosition = mul(input.Position, instanceTransform);
    float4 viewPosition = mul(worldPosition, view);
    output.Position = mul(viewPosition, projection);

    // Compute lighting, using a simple Lambert model.
    float3 worldNormal = mul(input.Normal, instanceTransform);
    
    float diffuseAmount = max(-dot(worldNormal, lightDirection), 0);
    
    float3 lightingResult = saturate(diffuseAmount * diffuseLight + ambientLight);
    
    output.Color = float4(lightingResult, 1);

    // Copy across the input texture coordinate.
    output.TexCoord = input.TexCoord;

    return output;
};

// On Windows shader 3.0 cards, we can use hardware instancing, reading
// the per-instance world transform directly from a secondary vertex stream.
VS_OUTPUT HardwareInstancingVertexShader(VS_INPUT input,
                                         float4x4 instanceTransform : TEXCOORD1)
{
    return VertexShaderCommon(input, transpose(instanceTransform));
}

// All the different instancing techniques share this same pixel shader.
float4 PixelShaderFunction(VS_OUTPUT input) : COLOR0
{
    return input.Color;
}

// Windows instancing technique for shader 3.0 cards.
technique HardwareInstancing
{
    pass Pass1
    {
        VertexShader = compile vs_3_0 HardwareInstancingVertexShader();
        PixelShader = compile ps_3_0 PixelShaderFunction();
    }
}